<?php
namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Cache;
use Log;

//define your token
define("TOKEN", "ac16f622c0c8e092caee670a6665006e");
define("APPID", "wxa65e84835e336e0c");
define("APPSECRET", "9dd56220e12aad89c790c8a1129848b6");

class WxController extends Controller
{
	/**
	 * 处理微信请求
	 */
	public function doDefault()
	{
		$this->responsePostMessageFromWeixin();
	}

	public function doView()
	{
		return response()->json(['hello'=>"myview"]);
	}

	public function test()
	{
		return response()->json(['test'=>$this->getAccessToken()]);
	}

	public function sendText()
	{
		$url = sprintf("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s", $this->getAccessToken());
		$openid = "oZICrjuL9OqSX4dfW8Gz2fMGMSLs";		
		$jsondata = json_encode(['touser'=>$openid, 'msgtype'=>'text', 'text'=>['content'=>'Hello World '.date("Y/m/d H:i:s")]]);
		$sendResult = json_decode(self::curl($url, $jsondata));
		self::kflog($sendResult);
	}

	public function valid(Request $request)
    {     
		$signature = $request->input("signature");
        $timestamp = $request->input("timestamp");
        $nonce = $request->input("nonce");
        //valid signature , option
        if($this->checkSignature($signature, $timestamp, $nonce)){
        	echo $request->input("echostr");
        	exit;
        }
    }

	private function responsePostMessageFromWeixin()
	{
		$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
      	//extract post data
		if (!empty($postStr)){
                /* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
                   the best way is to check the validity of xml by yourself */
            libxml_disable_entity_loader(true);
            $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);

			switch($postObj->MsgType)
			{
				case "text":
					$this->handlerTextMessage($postObj);
					break;
				case "event":
					$this->handlerEventMessage($postObj);
					break;
				default: 
					echo "";
					break;
			}
		}
	}

	private function handlerTextMessage($message)
	{

	}

	private function handlerEventMessage($message)
	{
		
	}
	
	public function resetClientMenu()
	{	
		$token = $this->getAccessToken();
		$redirect_uri = urlencode("http://120.25.237.238/view");
		$url = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=$token";
		$this->curl($url);
		$appid = APPID;
		$buttons =<<<eof
		{
			"button": [
				{
				"type": "view", 
				"name": "我的手环", 
				"url": "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$appid}&redirect_uri={$redirect_uri}&response_type=code&scope=snsapi_base&state=bracelet#wechat_redirect"
				},
				{
				"type": "click", 
				"name": "排行榜", 
				"key": "ranking"
				}
		]}
eof;
		$url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=$token";
		$this->curl($url, $buttons);      
	}
	/**
	 * 主动发送信息给设备
	 * @param $device_type 设备类型，目前为“公众账号原始ID”
	 * @param $device_id 设备ID
	 * @param $open_id	微信用户账号的openid
	 * @param $content	消息内容，BASE64编码
	 * @return void
	 */
	private function sendMessageToDevice($device_type, $device_id, $open_id, $content)
	{
		$url = sprintf("https://api.weixin.qq.com/device/transmsg?access_token=%s", $this->getAccessToken());
		$jsondata = json_encode(['device_type'=>$device_type, 'device_id'=>$device_id, 'open_id'=>$openid, 'content'=>base64_encode($content)]);
		$sendResult = json_decode(self::curl($url, $jsondata));
		Log::info(sprintf("result %s, send msg to device %s, open_id %s, content %s", 
			isset($sendResult->errmsg) ? 'fail '.$sendResult->errmsg : 'ok' , $device_id, $open_id, $content));
	}

	private function getMessageFromDevice()
	{
		$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
		if (! empty($postStr))
		{
			libxml_disable_entity_loader(true);
			/*
			<xml>
				<ToUserName><![CDATA[%s]]></ToUserName>
				<FromUserName><![CDATA[%s]]></FromUserName>
				<CreateTime>%u</CreateTime>
				<MsgType><![CDATA[%s]]></MsgType>
				<DeviceType><![CDATA[%s]]></DeviceType>
				<DeviceID><![CDATA[%s]]></DeviceID>
				<SessionID>%u</SessionID>
				<Content><![CDATA[%s]]></Content>
			</xml>
			 */
			$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
			$fromUsername = $postObj->FromUserName;
			$toUsername = $postObj->ToUserName;
			$msgType = $postObj->MsgType;
			$sessionId = $postObj->SessionId;
			$deviceId = $postObj->DeviceId;
			$deviceType = $postObj->DeviceType;
			$time = time();
			// @todo $content 对设备发送来的数据根据协议进行业务逻辑处理
			$content = base64_decode($postObj->Content);

			$response = "<xml>
						<ToUserName><![CDATA[%s]]></ToUserName>
						<FromUserName><![CDATA[%s]]></FromUserName>
						<CreateTime>%u</CreateTime>
						<MsgType><![CDATA[%s]]></MsgType>
						<DeviceType><![CDATA[%s]]></DeviceType>
						<DeviceID><![CDATA[%s]]></DeviceID>
						<SessionID>%u</SessionID>
						<Content><![CDATA[%s]]></Content>
					</xml>";
			echo sprintf($response, $toUsername, $fromUsername, $time, $msgType, $deviceType, $deviceId, $sessionId, base64_encode($content));
			exit;
		}
	}
	

    public function responseMsg()
    {
		//get post data, May be due to the different environments
		$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];

      	//extract post data
		if (!empty($postStr)){
                /* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
                   the best way is to check the validity of xml by yourself */
                libxml_disable_entity_loader(true);
              	$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
                $fromUsername = $postObj->FromUserName;
                $toUsername = $postObj->ToUserName;
                $keyword = trim($postObj->Content);
                $time = time();
                $textTpl = "<xml>
							<ToUserName><![CDATA[%s]]></ToUserName>
							<FromUserName><![CDATA[%s]]></FromUserName>
							<CreateTime>%s</CreateTime>
							<MsgType><![CDATA[%s]]></MsgType>
							<Content><![CDATA[%s]]></Content>
							<FuncFlag>0</FuncFlag>
							</xml>";             
				if(!empty( $keyword ))
                {
              		$msgType = "text";
                	$contentStr = "Welcome to wechat world!";
                	$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
                	echo $resultStr;
                }else{
                	echo "Input something...";
                }
				exit;

        }else {
        	echo "";
        	exit;
        }
    }
	
	private static function kflog($result, $msgtype='text')
	{
		$type = $result->errcode == 0 ? 'info' : 'error';
		Log::$type(sprintf("kf send %s msg, errcode %d, errmsg %s", $msgtype, $result->errcode, $result->errmsg));
	}

	private function getAccessToken()
	{
		$key = "access_token";
		$access_token = Cache::get($key);
		if (is_null($access_token))
		{
			$url = sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", APPID, APPSECRET);
			$result = json_decode(self::curl($url));
			
			// @todo retry 3 times
			if (isset($result->access_token))
			{
				Log::info(sprintf("get access token, access_token: %s, expires_in: %d", $result->access_token, $result->expires_in));
				Cache::put($key, $result->access_token, 118);
				$access_token = Cache::get($key);
			}
			else
			{
				Log::warning(sprintf("get access token, errmsg: %s, errcode: %d", $result->errmsg, $result->errcode));
				$access_token = false;
			}
		}
		return $access_token;
	}

	/* 发起curl请求 */
	private static function curl($url,$json_data=false)
	{
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);  // 要求结果为字符串且输出到屏幕上
		curl_setopt($ch, CURLOPT_TIMEOUT, 30);
		if ($json_data) 
		{
			curl_setopt($ch, CURLOPT_POST, 1);  // post 提交方式
			curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data);
		}
		$output = curl_exec($ch);
		curl_close($ch);
		return $output;
	}
		
	private function checkSignature($signature, $timestamp, $nonce)
	{
        // you must define TOKEN by yourself
        if (!defined("TOKEN")) {
            throw new Exception('TOKEN is not defined!');
        }
        		
		$token = TOKEN;
		$tmpArr = array($token, $timestamp, $nonce);
        // use SORT_STRING rule
		sort($tmpArr, SORT_STRING);
		$tmpStr = implode( $tmpArr );
		$tmpStr = sha1( $tmpStr );
		
		if( $tmpStr == $signature ){
			return true;
		}else{
			return false;
		}
	}
}

?>